package com.hbzhou.open.flowcamera;

import com.hbzhou.open.flowcamera.constant.Constants;
import com.hbzhou.open.flowcamera.listener.CaptureListener;
import com.hbzhou.open.flowcamera.util.CheckPermission;
import com.hbzhou.open.flowcamera.util.DeviceUtil;
import com.hbzhou.open.flowcamera.util.ValueAnimator;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.components.Component;
import ohos.agp.render.Arc;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.multimodalinput.event.TouchEvent;
import ohos.utils.IntervalTimer;

import static com.hbzhou.open.flowcamera.JCameraView.BUTTON_STATE_BOTH;
import static com.hbzhou.open.flowcamera.JCameraView.BUTTON_STATE_ONLY_CAPTURE;
import static com.hbzhou.open.flowcamera.JCameraView.BUTTON_STATE_ONLY_RECORDER;

/**
 * author hbzhou
 * date 2019/12/13 10:49
 */
public class CaptureButton extends Component implements Component.DrawTask, Component.TouchEventListener {
    public static final int STATE_IDLE = 0x001; // 空闲状态
    public static final int STATE_PRESS = 0x002; // 按下状态
    public static final int STATE_LONG_PRESS = 0x003; // 长按状态
    public static final int STATE_RECORDERING = 0x004; // 录制状态
    public static final int STATE_BAN = 0x005; // 禁止状态

    private int mProgress_color = 0xEE16AE16; // 进度条颜色
    private int mOutside_color = 0xEEDCDCDC; // 外圆背景色
    private int mInside_color = 0xFFFFFFFF; // 内圆背景色

    private int mPressState; // 当前按钮状态
    private int mButton_state; // 按钮可执行的功能状态（拍照,录制,两者）

    private EventHandler mHandler;
    private float mEvent_Y; // Touch_Event_Down时候记录的Y值

    private Paint mPaint;

    private float mStrokeWidth; // 进度条宽度
    private int mOutside_add_size; // 长按外圆半径变大的Size
    private int mInside_reduce_size; // 长安内圆缩小的Size

    // 中心坐标
    private float mCenter_X;
    private float mCenter_Y;

    private float mButton_radius; // 按钮半径
    private float mButton_outside_radius; // 外圆半径
    private float mButton_inside_radius; // 内圆半径

    private float mProgress; // 录制视频的进度
    private long mDuration; // 录制视频最大时间长度
    private int mMin_duration; // 最短录制时间限制
    private int mRecorded_time; // 记录当前录制的时间

    private RectFloat mRectF;

    private LongPressRunnable mLongPressRunnable; // 长按后处理的逻辑Runnable
    private CaptureListener mCaptureListener; // 按钮回调接口
    private RecordCountDownTimer mTimer; // 计时器
    private boolean isTimeCancel = true; // IntervalTimer 计时器即使cancel了，还会走onFinish()

    public CaptureButton(Context context) {
        super(context);
    }

    public CaptureButton(Context context, int size) {
        super(context);
        int buttonSize = size; // 按钮大小
        mButton_radius = size / 2.0f;

        mButton_outside_radius = mButton_radius;
        mButton_inside_radius = mButton_radius * 0.75f;

        mStrokeWidth = size / 15f;
        mOutside_add_size = size / 5;
        mInside_reduce_size = size / 8;

        mPaint = new Paint();
        mPaint.setAntiAlias(true);

        mProgress = 0;
        mLongPressRunnable = new LongPressRunnable();

        mPressState = STATE_IDLE; // 初始化为空闲状态
        mButton_state = BUTTON_STATE_BOTH; // 初始化按钮为可录制可拍照
        mDuration = 10 * 1000; // 默认最长录制时间为10s
        mMin_duration = 1500; // 默认最短录制时间为1.5s

        mCenter_X = (buttonSize + mOutside_add_size * 2) / 2f;
        mCenter_Y = (buttonSize + mOutside_add_size * 2) / 2f;

        mRectF =
                new RectFloat(
                        mCenter_X - (mButton_radius + mOutside_add_size - mStrokeWidth / 2),
                        mCenter_Y - (mButton_radius + mOutside_add_size - mStrokeWidth / 2),
                        mCenter_X + (mButton_radius + mOutside_add_size - mStrokeWidth / 2),
                        mCenter_Y + (mButton_radius + mOutside_add_size - mStrokeWidth / 2));

        mTimer = new RecordCountDownTimer(mDuration, mDuration / 360L); // 录制定时器
        addDrawTask(this);
        setTouchEventListener(this);
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        mPaint.setStyle(Paint.Style.FILL_STYLE);

        mPaint.setColor(new Color(mOutside_color)); // 外圆（半透明灰色）
        canvas.drawCircle(mCenter_X, mCenter_Y, mButton_outside_radius, mPaint);

        mPaint.setColor(new Color(mInside_color)); // 内圆（白色）
        canvas.drawCircle(mCenter_X, mCenter_Y, mButton_inside_radius, mPaint);

        // 如果状态为录制状态，则绘制录制进度条
        if (mPressState == STATE_RECORDERING) {
            mPaint.setColor(new Color(mProgress_color));
            mPaint.setStyle(Paint.Style.STROKE_STYLE);
            mPaint.setStrokeWidth(mStrokeWidth);
            canvas.drawArc(mRectF, new Arc(-90, mProgress, false), mPaint);
        }
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent event) {
        switch (event.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                if (event.getPointerCount() > 1 || mPressState != STATE_IDLE) {
                    if (mCaptureListener != null) {
                        mCaptureListener.onError(
                                "click button By state is STATE_BAN " + "or TouchEvent getPointerCount > 1",
                                Constants.ERROR_TYPE_PICTURE);
                    }
                    break;
                }

                mEvent_Y = event.getPointerPosition(event.getIndex()).getY();
                mPressState = STATE_PRESS; // 修改当前状态为点击按下

                // 判断按钮状态是否为可录制状态
                if ((mButton_state == BUTTON_STATE_ONLY_RECORDER || mButton_state == BUTTON_STATE_BOTH)) {
                    postDelayed(mLongPressRunnable); // 同时延长500启动长按后处理的逻辑Runnable
                }
                break;
            case TouchEvent.POINT_MOVE:
                if (mCaptureListener != null
                        && mPressState == STATE_RECORDERING
                        && (mButton_state == BUTTON_STATE_ONLY_RECORDER || mButton_state == BUTTON_STATE_BOTH)) {
                    // 记录当前Y值与按下时候Y值的差值，调用缩放回调接口
                    float pointY = event.getPointerPosition(event.getIndex()).getY();
                    float zoom = mEvent_Y - pointY;
                    mCaptureListener.recordZoom(zoom);
                }
                break;
            case TouchEvent.PRIMARY_POINT_UP:
                // 根据当前按钮的状态进行相应的处理
                handlerUnPressByState();
                break;
        }
        return true;
    }

    private void postDelayed(Runnable runnable) {
        if (mHandler == null) {
            mHandler = new EventHandler(EventRunner.getMainEventRunner());
        }
        mHandler.postTask(runnable, 500);
    }

    private void removeCallbacks(Runnable runnable) {
        if (mHandler == null) {
            return;
        }
        mHandler.removeTask(runnable);
    }

    // 当手指松开按钮时候处理的逻辑
    private void handlerUnPressByState() {
        removeCallbacks(mLongPressRunnable); // 移除长按逻辑的Runnable
        // 根据当前状态处理
        switch (mPressState) {
            // 当前是点击按下
            case STATE_PRESS:
                if (mCaptureListener != null
                        && (mButton_state == BUTTON_STATE_ONLY_CAPTURE || mButton_state == BUTTON_STATE_BOTH)) {
                    startCaptureAnimation(mButton_inside_radius);
                } else {
                    mPressState = STATE_IDLE;
                }
                break;
            // 当前是长按状态
            case STATE_RECORDERING:
                if (mTimer != null) {
                    mTimer.cancel(); // 停止计时器
                    isTimeCancel = true;
                }
                recordEnd(); // 录制结束
                break;
        }
    }

    // 录制结束
    private void recordEnd() {
        if (mCaptureListener != null) {
            if (mRecorded_time < mMin_duration) {
                mCaptureListener.recordShort(mRecorded_time); // 回调录制时间过短
            } else {
                mCaptureListener.recordEnd(mRecorded_time); // 回调录制结束
            }
        }
        resetRecordAnimation();
    }

    // 重制状态
    private void resetRecordAnimation() {
        mPressState = STATE_BAN;
        mProgress = 0; // 重制进度
        isTimeCancel = true;
        invalidate();
        // 还原按钮初始状态动画
        startRecordAnimation(mButton_outside_radius, mButton_radius, mButton_inside_radius, mButton_radius * 0.75f);
    }

    // 内圆动画
    private void startCaptureAnimation(float insideStart) {
        ValueAnimator insideAnimation = ValueAnimator.ofFloat(insideStart, insideStart * 0.75f, insideStart);
        insideAnimation.addUpdateListener(
                (animation, value) -> {
                    mButton_inside_radius = (float) value;
                    invalidate();
                });
        insideAnimation.addListener(
                new ValueAnimator.AnimatorStatusChangeListener() {
                    @Override
                    public void onEnd(ValueAnimator animator, ValueAnimator.State state) {
                        if (state == ValueAnimator.State.ANIM_END) {
                            mCaptureListener.takePictures();
                            mPressState = STATE_BAN;
                        }
                    }

                    @Override
                    public void start(ValueAnimator animator, ValueAnimator.State state) {
                    }
                });
        insideAnimation.setDuration(100);
        insideAnimation.start();
    }

    // 内外圆动画
    private void startRecordAnimation(float outside_start, float outside_end, float inside_start, float inside_end) {
        ValueAnimator outsideAnimation = ValueAnimator.ofFloat(outside_start, outside_end);
        ValueAnimator insideAnimation = ValueAnimator.ofFloat(inside_start, inside_end);
        // 外圆动画监听
        outsideAnimation.addUpdateListener(
                (animation, value) -> {
                    mButton_outside_radius = (float) value;
                    invalidate();
                });
        // 内圆动画监听

        insideAnimation.addUpdateListener(
                (animation, value) -> {
                    mButton_inside_radius = (float) value;
                    invalidate();
                });
        AnimatorGroup animatorGroup = new AnimatorGroup();

        Animator[] outA = outsideAnimation.getAnimatorValue();
        Animator[] inA = insideAnimation.getAnimatorValue();

        animatorGroup.setStateChangedListener(
                new Animator.StateChangedListener() {
                    @Override
                    public void onStart(Animator animator) {
                    }

                    @Override
                    public void onStop(Animator animator) {
                    }

                    @Override
                    public void onCancel(Animator animator) {
                    }

                    @Override
                    public void onEnd(Animator animator) {
                        onAnimationEnd();
                    }

                    @Override
                    public void onPause(Animator animator) {
                    }

                    @Override
                    public void onResume(Animator animator) {
                    }
                });
        animatorGroup.runParallel(DeviceUtil.concat(outA, inA));
        animatorGroup.setDuration(100);
        animatorGroup.start();
    }

    private void onAnimationEnd() {
        if (mPressState == STATE_LONG_PRESS) {
            if (mCaptureListener != null) {
                mCaptureListener.recordStart();
            }
            isTimeCancel = false;
            mPressState = STATE_RECORDERING;
            mTimer.schedule();
        }
    }

    // 更新进度条
    private void updateProgress(long millisUntilFinished) {
        mRecorded_time = (int) (mDuration - millisUntilFinished);
        mProgress = 360f - millisUntilFinished / (float) mDuration * 360f;
        mHandler.postTask(this::invalidate);
    }

    // 录制视频计时器
    private class RecordCountDownTimer extends IntervalTimer {
        RecordCountDownTimer(long millisInFuture, long countDownInterval) {
            super(millisInFuture, countDownInterval);
        }

        @Override
        public void onInterval(long millisUntilFinished) {
            updateProgress(millisUntilFinished);
        }

        @Override
        public void onFinish() {
            if (!isTimeCancel) {
                updateProgress(0);
                recordEnd();
            }
        }
    }

    // 长按线程
    private class LongPressRunnable implements Runnable {
        @Override
        public void run() {
            mPressState = STATE_LONG_PRESS; // 如果按下后经过500毫秒则会修改当前状态为长按状态
            // 没有录制权限
            if (CheckPermission.getRecordState() != CheckPermission.STATE_SUCCESS) {
                mPressState = STATE_IDLE;
                if (mCaptureListener != null) {
                    mCaptureListener.onError("record no permission", Constants.ERROR_TYPE_RECORD);
                    return;
                }
            }
            // 启动按钮动画，外圆变大，内圆缩小
            startRecordAnimation(
                    mButton_outside_radius,
                    mButton_outside_radius + mOutside_add_size,
                    mButton_inside_radius,
                    mButton_inside_radius - mInside_reduce_size);
        }
    }

    /**
     * 设置最长录制时间
     *
     * @param duration int
     */
    public void setDuration(int duration) {
        if (duration == 0) {
            duration = 10 * 1000;
        }
        this.mDuration = duration;
        mTimer = new RecordCountDownTimer(duration, duration / 360); // 录制定时器
    }

    /**
     * 设置最短录制时间
     *
     * @param duration int
     */
    public void setMinDuration(int duration) {
        this.mMin_duration = duration;
    }

    /**
     * 设置回调接口
     *
     * @param captureListener CaptureListener
     */
    public void setCaptureListener(CaptureListener captureListener) {
        this.mCaptureListener = captureListener;
    }

    /**
     * 设置按钮功能（拍照和录像）
     *
     * @param state int
     */
    public void setButtonFeatures(int state) {
        this.mButton_state = state;
    }

    /**
     * 是否空闲状态
     *
     * @return boolean boolean
     */
    public boolean isIdle() {
        return mPressState == STATE_IDLE;
    }

    /**
     * 设置状态
     */
    public void resetState() {
        mPressState = STATE_IDLE;
    }

    /**
     * set Button Circle Color
     * @param inside_color int
     * @param outside_color int
     * @param progress_color int
     */
    public void setButtonCircleColor(int inside_color, int outside_color, int progress_color) {
        if (inside_color > 0) {
            this.mInside_color = inside_color;
        }
        if (outside_color > 0) {
            this.mOutside_color = outside_color;
        }
        if (progress_color > 0) {
            this.mProgress_color = progress_color;
        }
    }
}
